/*
 * CellSubSystem.cpp
 *
 *  Created on: Apr 25, 2017
 *      Author: zhangjf
 */

#include <Poco/Util/Application.h>
#include <Poco/Dynamic/Var.h>
#include <Poco/JSON/Object.h>
#include <Poco/JSON/Parser.h>
#include <Poco/Exception.h>
#include <Poco/Bugcheck.h>
#include <Poco/Logger.h>
#include <Poco/File.h>
#include <Poco/Path.h>
#include <Poco/Zip/ZipArchive.h>
#include <Poco/Zip/ZipStream.h>
#include <Poco/StreamCopier.h>
#include <fstream>
#include <sstream>

#include "Helper.h"

using namespace Poco;
using namespace Poco::JSON;
using namespace Poco::Dynamic;
using namespace Poco::Zip;
using namespace util;

#include "DatabaseSubsystem.h"
#include "CellSubsystem.h"

using namespace database;
using namespace cell;

namespace cell
{

const std::string CellSubsystem::_spc_original_path = "/data/original/spc";	//"/data/specific";
const std::string CellSubsystem::_spc_file_path = "/data/ncs/spc";	//"/data/specific";
const std::string CellSubsystem::_name = "CellSubsystem";
CellSubsystem* CellSubsystem::_pInstance = nullptr;

std::vector<std::tuple<std::string, std::string>> CellSubsystem::_systemCellList
{
	// CellType, spc file name, the path:
	std::make_tuple("SystemSettings", "SystemSettings.zip"),
	std::make_tuple("GlobalData", "GlobalData.zip"),
//	std::make_tuple("SystemLog", "SystemLog.zip"),
};

CellSubsystem::CellSubsystem()
: NCSSubsystem(name())
{
	if (_pInstance != nullptr)
		return;
	_pInstance = this;

	// TODO Auto-generated constructor stub
//	std::string fname = std::string(Application::instance().name()) + ".log";
//	Helper::initLogger(logger(), fname);

	poco_information(logger(), __func__ + std::string(": ") + "ok");
}

CellSubsystem::~CellSubsystem()
{
	// TODO Auto-generated destructor stub
}

void CellSubsystem::initialize(Application& self)
{
	DatabaseSubsystem& db = DatabaseSubsystem::instance();
	//check system fixed cell: SystemSettings, GlobalData, LogGroup
	for (auto item : _systemCellList)
	{
		//bool blRet;
		std::string cellType = std::get<0>(item);
		std::string fileName = std::get<1>(item);
		Path pathSpc(_spc_original_path, fileName);
		//check CellType whether exist in database or not
		if (!db.isRegisterCellType(cellType))
		{	// celltype not exist in database
			std::string strPath = pathSpc.toString();
			registerCellType(cellType, strPath);
		}

		// check app of celltype has created
		// todo:: if (db.getCounterWithAppType())
		// add app
		// todo:: std::string appType = db.getAppTypeWithCellType(cellType);
		// todo:: blRet = db.getCounterWithAppType(appType, counter);
		//poco_assert(blRet);
		UInt32 counter = 0;
		if (!db.getAppCountWithCellType(cellType, counter))
		{
			poco_information(logger(), "error: getAppCountWithCellType(" + cellType + ") failed");
			throw Exception("CellSubsystem::initialize() failed");
		}

		if (counter == 0)
		{
			std::string appName = "";
			UInt32 appID;
			if (!addApp(cellType, appName, appID))
			{
				poco_information(logger(), "error: addApp(" + cellType + ") failed");
				throw Exception("CellSubsystem::initialize() failed");
			}
		}
		else if (counter > 1)
		{
			poco_information(logger(), "error: " + cellType + " has multiple instance");
			throw Exception("CellSubsystem::initialize() failed");
		}

	}
	poco_information(logger(), __func__ + std::string(": ") + "ok");
}

bool CellSubsystem::addApp(std::string& cellType, std::string& appName, UInt32& appID)
{
	bool blRet = true;

	DatabaseSubsystem& db = DatabaseSubsystem::instance();

	blRet = db.addApp(cellType, appName, appID);

	return blRet;
}

bool CellSubsystem::registerCellType_1(std::string& cellType, string& zipFile, Object::Ptr& joCellInfo)
{
	bool blRet = true;

	string type = joCellInfo->getValue<string>("cell_type");
	if (cellType != type)
	{
		throw Exception("cell_type of exported spc file is not matched with the type of cell");
	}

	DatabaseSubsystem& db = DatabaseSubsystem::instance();

	db.registerCellType(cellType, zipFile, joCellInfo);

	return blRet;
}

bool CellSubsystem::registerCellType(std::string& cellType, std::string& zipFile)
{
	bool blRet = true;
	std::string strBuf;

	std::string strSubFile("config.spc");
	Helper::readFileFromZip(zipFile, strSubFile, strBuf);

	poco_information(logger(), strBuf);

	try
	{
		Parser parser;
		Object::Ptr joCellInfo = parser.parse(strBuf).extract<Object::Ptr>();

		registerCellType_1(cellType, zipFile, joCellInfo);
	}
	catch (JSONException& exc)
	{
		poco_information(logger(), "error: " + exc.displayText());
		blRet = false;
	}
	//ifs.close();
	//Object::Ptr joCellInfo = json.extract<Poco::JSON::Object::Ptr>();

	// todo:: add celltype to db
	//blRet = db.registerCellType(joCellInfo);
	//poco_assert(blRet);

	return blRet;
}

void CellSubsystem::uninitialize()
{
}

} /* namespace cell */
